drun: |
~/ Blog How i fixed qBittorrent and Gluetun constantly going unhealthy

Introduction

qBittorrent and Gluetun was the first service that I self hosted, and it was a nightmare to setup, mainly because Gluetun would constantly go unhealthy and seeding would stop. Here I will share my docker compose file and explain how I fixed the issue, to the point where it goes unhealthy maybe once in a month instead of multiple times a day.

The healthcheck duration

This was crucial. I don't know if newer versions of Gluetun fixed the issue, but back when I originally set it up the default values were way too short, and this led to Gluetun failing constantly. The fix, found digging in GitHub issues, was to set custom values for the VPN health check:


HEALTH_VPN_DURATION_INITIAL=120s
HEALTH_VPN_DURATION=30s
HEALTH_TARGET_ADDRESS=cloudflare.com:80
            

OpenVPN instead of WireGuard

The second most important fix was to switch from WireGuard to OpenVPN. I was reluctant because I thought the performance drop would be noticeable, but it really wasn't. OpenVPN was the only stable option. Even the increased healthcheck duration didn't work for WireGuard in my case.

Libtorrent v1

To this day I still don't know if it was needed or not, but from my previous researches picking this as the Docker image was a better choice in terms of stability. But just like with every other element, I suggest you test this yourself before.

Useful commands to troubleshoot

Grab VPN IP

docker exec -it gluetun wget -qO- ifconfig.me/ip

Grab forwarded port

docker logs gluetun 2>&1 | grep -i 'port forwarded'

My docker compose

services:
  gluetun:
    image: qmcgaw/gluetun:v3
    container_name: gluetun
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    ports:
      - "8080:8080/tcp" # qbittorrent
    environment:
      - TZ=
      - UPDATER_PERIOD=24h
      - VPN_SERVICE_PROVIDER=protonvpn
      - VPN_TYPE=${VPN_TYPE}
      - BLOCK_MALICIOUS=off
      - OPENVPN_USER=${OPENVPN_USER}
      - OPENVPN_PASSWORD=${OPENVPN_PASSWORD}
      - OPENVPN_CIPHERS=AES-256-GCM
      # - WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
      - PORT_FORWARD_ONLY=on
      - VPN_PORT_FORWARDING=on
      - VPN_PORT_FORWARDING_UP_COMMAND=/bin/sh -c 'P="{{PORTS}}"; P="$${P%%,*}"; P="$${P%% *}"; wget -qO- --retry-connrefused --waitretry=1 --timeout=10 -t 30 --post-data "json={\"listen_port\":$${P}}" http://127.0.0.1:8080/api/v2/app/setPreferences >/dev/null && echo "qB listen_port set to $${P}"'
      - SERVER_COUNTRIES=${SERVER_COUNTRIES}
      - OPENVPN_MSSFIX=1400
      - VPN_MTU=1400
      - HEALTH_VPN_DURATION_INITIAL=120s
      - HEALTH_VPN_DURATION=30s
      - HEALTH_TARGET_ADDRESS=cloudflare.com:80
    volumes:
      - /home/user/docker/qbittorrent-gluetun/gluetun/config:/gluetun
    networks:
      - vpn_net
    restart: unless-stopped

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:libtorrentv1
    container_name: qbittorrent
    depends_on:
      - gluetun
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Rome
      - WEBUI_PORT=8080
    volumes:
      - /home/user/docker/qbittorrent-gluetun/qbittorrent/config:/config
      - /mnt/nas/media/torrents/downloads:/downloads
    restart: unless-stopped
    network_mode: "service:gluetun"

  # Gluetun WEB-UI is honestly not needed, I just use it to quickly check the forwarded port without using the terminal.
  gluetun-webui:
    image: scuzza/gluetun-webui:latest
    container_name: gluetun-webui
    depends_on:
      - gluetun
    ports:
      - "3002:3000"
    environment:
      - GLUETUN_CONTROL_URL=http://gluetun:8000
    networks:
      - vpn_net
    restart: unless-stopped
    read_only: true
    tmpfs:
      - /tmp
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
      interval: 30s
      timeout: 5s
      start_period: 10s
      retries: 3

networks:
  vpn_net:
    driver: bridge